package com.example.demo.service.impl;

import com.example.demo.dao.OrderDAO;
import com.example.demo.dao.ProductDAO;
import com.example.demo.dao.ProductDetailDAO;
import com.example.demo.dao.UserDAO;
import com.example.demo.dataobject.OrderDO;
import com.example.demo.dataobject.ProductDO;
import com.example.demo.dataobject.ProductDetailDO;
import com.example.demo.dataobject.UserDO;
import com.example.demo.model.Order;
import com.example.demo.model.OrderStatus;
import com.example.demo.model.Paging;
import com.example.demo.model.ProductDetail;
import com.example.demo.model.User;
import com.example.demo.param.QueryOrderParam;
import com.example.demo.service.OrderService;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private UserDAO userDAO;
    @Autowired
    private ProductDAO productDAO;
    @Autowired
    private ProductDetailDAO productDetailDAO;
    @Autowired
    private OrderDAO orderDAO;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public Order add(Order order) {
        if (order == null) {
            return null;
        }
        //生成唯一主键id
        order.setId(UUID.randomUUID().toString().replace("-", ""));
        //初始化订单状态
        order.setStatus(OrderStatus.WAIT_BUYER_PAY);
        //生成订单号
        order.setOrderNumber(createOrderNumber());
        //写入数据库
        orderDAO.insert(order.toDO());
        return order;
    }
    /**
     * 生成唯一订单号
     * 16位订单号，日期+序号 如202506010808 0001
     * @return String
     */
    private java.lang.String createOrderNumber() {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
        java.lang.String date = dateTimeFormatter.format(LocalDateTime.now());
        RAtomicLong atomicLong = redissonClient.getAtomicLong("OrderNumber");
        atomicLong.expire(1, TimeUnit.MINUTES);//设置过期时间
        return date+ java.lang.String.format("%04d", atomicLong.getAndIncrement());
    }

    @Override
    public Paging<Order> queryRecentPay(QueryOrderParam param) {
        if (param == null) {
            return null;
        }
        //分页信息
        Paging<Order> result = pagination(param);

        //订单
        List<OrderDO> orderDOS=orderDAO.pageQuery(param);
        List<Order> orders = new ArrayList<>();
        List<String> productDetailIds = new ArrayList<>();
        List<Long> userIds = new ArrayList<>();
        orderDOS.forEach(orderDO -> {
            orders.add(orderDO.toModel());
            productDetailIds.add(orderDO.getProductDetailId());
            userIds.add(orderDO.getUserId());
        });

        //用户
        List<UserDO> userDOS = userDAO.findByIds(userIds);
        Map<Long,User> userMap=new HashMap<>();
        userDOS.forEach(userDO -> {userMap.put(userDO.getId(), userDO.toModel());});
        //商品信息
        List<ProductDetailDO> productDetailDOS=productDetailDAO.selectByIds(productDetailIds);
        Map<String,ProductDetail> productDetailMap=new HashMap<>();
        productDetailDOS.forEach(productDetailDO -> {productDetailMap.put(productDetailDO.getId(), productDetailDO.toModel());});

        orders.forEach(order -> {
            order.setProductDetail(productDetailMap.get(order.getProductDetailId()));
            order.setUser(userMap.get(order.getUserId()));
        });

        result.setData(orders);
        return result;
    }

    /**
     * 处理分页信息中的数据
     * @param param
     * @return
     */
    private Paging<Order> pagination(QueryOrderParam param) {
        Paging<Order> paging = new Paging<>();
        paging.setPageNum(param.getPageNum());//当前页数
        paging.setPageSize(param.getPageSize());//每页数量
        //总记录数
        paging.setTotalCount(orderDAO.count(param));
        if (paging.getTotalCount() <= 0) {
            return paging;
        }
        paging.setTotalPage((int) Math.ceil(paging.getTotalCount() / param.getPageSize()));//总页数=总记录数/每页数量
        //Math.ceil()方法返回大于或等于指定表达式的最小整数,返回double类型
        //还可以通过(a+b-1)/b的方式实现向上取整
        return paging;
    }

    @Override
    public Order getByOrderNumber(String orderNumber) {
        if (StringUtils.isEmpty(orderNumber)) {
            return null;
        }
        OrderDO orderDO = orderDAO.selectByOrderNumber(orderNumber);
        if (orderDO != null) {
            Order order = orderDO.toModel();
            return order;
        }
        return null;
    }

    @Override
    public Order updateStatus(String orderNumber, OrderStatus orderStatus) {
        OrderDO orderDO = orderDAO.selectByOrderNumber(orderNumber);
        if (orderDO == null) {
            return null;
        }
        orderDO.setStatus(orderStatus.toString());
        orderDAO.updateStatusByOrderNumber(orderNumber, String.valueOf(orderStatus));
        return orderDO.toModel();
    }

    @Override
    public Order updateProductPersonNumber(String orderNumber) {
        OrderDO orderDO = orderDAO.selectByOrderNumber(orderNumber);
        if (orderDO == null) {
            return null;
        }
        //获取分布式锁
        RLock transferLock = redissonClient.getLock("PURCHASE");
        transferLock.lock();
        try {
            //1.商品库存-1
            ProductDetailDO productDetailDO = productDetailDAO.selectById(orderDO.getProductDetailId());
            if (productDetailDO == null) {
                return null;
            }
            productDetailDO.setStock(productDetailDO.getStock() - 1);
            productDetailDAO.updateById(productDetailDO);

            //2.商品购买人数+1
            ProductDO productDO = productDAO.selectById(productDetailDO.getProductId());
            productDO.setPurchase(productDO.getPurchase() + 1);
            productDAO.updateById(productDO);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            transferLock.unlock();
        }
        return orderDO.toModel();
    }

}
